{$O-}
unit uSplineNavigator;

interface
uses
  VectorGeometry, VectorLists, Spline;
type
//------------------------------------------------------------------------------
  TSplineNavigator = class
  protected
    fList: TVectorList;
    fCubicSpline: TCubicSpline;
    function GetBasePointsCount: Integer;
  public
    property BasePointsCount: Integer read GetBasePointsCount;
    Function Add3d(const x, y, z: Single): Integer;
    Function Add2d(const x, y: Single): Integer; // z = 0
    Function GetBasePointByIndex(const aIndex: Integer): TVector; // base points
    Function GetPointByUnit(const aUnit: Single): TVector;
    Function GetSlopeByUnit(const aUnit: Single): TVector;
    Procedure DeletePoints;
    Procedure CreateCubicSpline;
    Constructor Create;
    Destructor Destroy; override;
  end;
//------------------------------------------------------------------------------
implementation
uses
  SysUtils;
//------------------------------------------------------------------------------
function TSplineNavigator.GetBasePointsCount: Integer;
begin
  if fList <> nil then
    result := fList.Count
  else
    result := 0;  
end;
//------------------------------------------------------------------------------
Function TSplineNavigator.Add3d(const x, y, z: Single): Integer;
begin
  result := fList.Add(x, y, z, 1);
end;
//------------------------------------------------------------------------------
Function TSplineNavigator.Add2d(const x, y: Single): Integer; // z = 0
begin
  result := fList.Add(x, y, 0, 1);
end;
//------------------------------------------------------------------------------
Function TSplineNavigator.GetBasePointByIndex(const aIndex: Integer): TVector; // base points
begin
  result := fList.Items[aIndex];
end;
//------------------------------------------------------------------------------
Function TSplineNavigator.GetPointByUnit(const aUnit: Single): TVector;
begin
  result := fCubicSpline.SplineVector(aUnit * (fList.Count - 1));
end;
//------------------------------------------------------------------------------
Function TSplineNavigator.GetSlopeByUnit(const aUnit: Single): TVector;
begin
  result := VectorMake(fCubicSpline.SplineSlopeVector(aUnit * (fList.Count - 1)), 1);
end;
//------------------------------------------------------------------------------
Procedure TSplineNavigator.DeletePoints;
begin
  while fList.Count > 0 do
    fList.Pop;
end;
//------------------------------------------------------------------------------
Procedure TSplineNavigator.CreateCubicSpline;
var
  i: Integer;
  xa, ya, za : PFloatArray;
begin
  GetMem(xa, SizeOf(Single) * fList.Count);
  GetMem(ya, SizeOf(Single) * fList.Count);
  GetMem(za, SizeOf(Single) * fList.Count);
  for i := 0 to fList.Count - 1 do
  begin
    xa^[i] := fList.Items[i][0];
    ya^[i] := fList.Items[i][1];
    za^[i] := fList.Items[i][2];
  end;
  if fCubicSpline <> nil then
    FreeAndNil(fCubicSpline);
  fCubicSpline := TCubicSpline.Create(xa, ya, za, nil, fList.Count);
  FreeMem(xa);
  FreeMem(ya);
  FreeMem(za);
end;
//------------------------------------------------------------------------------
Constructor TSplineNavigator.Create;
begin
  inherited Create;
  fCubicSpline := nil;
  fList := TVectorList.Create;
end;
//------------------------------------------------------------------------------
Destructor TSplineNavigator.Destroy;
begin
  DeletePoints;
  inherited Destroy;
end;
//------------------------------------------------------------------------------
end.
